<template>
  <div class="map-page">
    <!-- 顶部栏 -->
    <div class="top-bar">
      <!-- 当前城市 -->
      <div class="city">当前地址：{{ lives.city }}</div>
      <!-- 搜索框 -->
      <div class="search-container">
        <el-input
          v-model="searchCity"
          placeholder="请搜索你所在的城市"
          prefix-icon="Search"
          clearable
          style="width: 240px"
          @change="handleSearchCity"
        />
      </div>
      <!--绘图下拉框 -->
      <div class="select-container">
        <el-select
          v-model="drawType"
          placeholder="选择绘制图形"
          style="width: 240px"
          clearable
          @change="handleDrawTypeChange"
        >
          <el-option label="直线" value="line"></el-option>
          <el-option label="圆形" value="circle"></el-option>
          <el-option label="多边形" value="polygon"></el-option>
          <el-option label="自由画笔" value="freehand"></el-option>
          <el-option label="清除绘图" value="clear"></el-option>
        </el-select>
      </div>
      <!-- 标记下拉框 -->
      <div class="select-container">
        <el-tooltip
          :disabled="currentZoom >= 13"
          content="请放大到13级以上才能添加标记"
          placement="top"
        >
          <el-select
            v-model="markerType"
            placeholder="选择标记类型"
            style="width: 240px"
            clearable
            :disabled="currentZoom < 13"
          >
            <el-option label="充电站" value="charging"></el-option>
            <el-option label="公交站" value="bus"></el-option>
            <el-option label="停车场" value="parking"></el-option>
            <el-option label="退出标记" value="exit"></el-option>
          </el-select>
        </el-tooltip>
      </div>
    </div>
    <!-- 地图容器 -->
    <div ref="mapContainer" class="map-container"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue'
import { getCityAdcode, getCityByIp } from './api/index.js'
import { ElMessage } from 'element-plus'

import { View, Map } from 'ol'
import 'ol/ol.css'
import TileLayer from 'ol/layer/Tile.js'
import { XYZ } from 'ol/source'
import VectorLayer from 'ol/layer/Vector.js'
import VectorSource from 'ol/source/Vector.js'
import GeoJSON from 'ol/format/GeoJSON.js'
import { Style, Fill, Stroke, Circle as CircleStyle } from 'ol/style.js'

// 绘图导入
import { Draw } from 'ol/interaction.js'
import Overlay from 'ol/Overlay.js'
import { getLength } from 'ol/sphere.js'
import { getCenter } from 'ol/extent.js'

//标记导入
import { Cluster } from 'ol/source'
import { Feature } from 'ol'
import Point from 'ol/geom/Point.js'
import { Icon, Text } from 'ol/style.js'
import AnimatedCluster from 'ol-ext/layer/AnimatedCluster.js'

const mapContainer = ref(null)
let map = null
const lives = ref({
  city: '',
})
const markerType = ref('')
const searchCity = ref('')
const drawType = ref('')

const overlay = ref(null)
const container = ref(null)
const currentZoom = ref(10)

let highlightLayer = null
let drawInteraction = null
let currentCityAdcode = null

let drawLayer = null
let drawSource = null

let markerLayer = null
let markerSource = null
let clusterSource = null
//初始化提示框
const initOverlay = () => {
  container.value = document.createElement('div')
  container.value.style.cssText = `
  background: pink;
  padding: 8px 12px;
  border-radius: 4px;
  color: #000;
  font-size: 14px;
  line-height: 1.5;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
  z-index: 1000;
  `
  container.value.innerHTML = '<div id="tooltip-content"></div>'
  overlay.value = new Overlay({
    element: container.value,
    autoPan: true,
    autoPanAnimation: {
      duration: 250,
    },
  })
  map.addOverlay(overlay.value)
}

// 初始化标记图层
const initMarkerLayer = () => {
  markerSource = new VectorSource() // 原始标记数据源
  clusterSource = new Cluster({
    // 创建聚合源
    distance: 40,
    source: markerSource,
  })

  markerLayer = new AnimatedCluster({
    animationDuration: 300,
    source: clusterSource,
    style: createMarkerStyle,
  })

  map.addLayer(markerLayer)
}

// 创建标记样式
const createMarkerStyle = (feature) => {
  const features = feature.get('features')
  const size = features ? features.length : 1

  if (size === 1) {
    const actualFeature = features ? features[0] : feature
    const type = actualFeature.get('type')

    if (!type) {
      return new Style({
        image: new CircleStyle({
          radius: 6,
          fill: new Fill({
            color: '#3399CC',
          }),
          stroke: new Stroke({
            color: '#fff',
            width: 2,
          }),
        }),
      })
    }

    let iconSrc = ''
    switch (type) {
      case 'charging':
        iconSrc = './充电站.png'
        break
      case 'bus':
        iconSrc = './公交站.png'
        break
      case 'parking':
        iconSrc = './停车场.png'
        break
      default:
        return new Style({
          image: new CircleStyle({
            radius: 6,
            fill: new Fill({
              color: '#3399CC',
            }),
            stroke: new Stroke({
              color: '#fff',
              width: 2,
            }),
          }),
        })
    }
    return new Style({
      image: new Icon({
        src: iconSrc,
        scale: 0.2,
      }),
    })
  } else {
    return new Style({
      image: new CircleStyle({
        radius: 15,
        fill: new Fill({
          color: 'rgba(0, 153, 255, 0.8)',
        }),
        stroke: new Stroke({
          color: '#fff',
          width: 2,
        }),
      }),
      text: new Text({
        text: size.toString(),
        fill: new Fill({
          color: '#fff',
        }),
        font: '12px sans-serif',
      }),
    })
  }
}
// 监听标记类型变化
watch(markerType, (newType) => {
  if (newType === 'exit') {
    map.un('click', addMarker)
    markerType.value = ''
  } else if (newType) {
    map.on('click', addMarker)
  }
})

// 添加标记函数
const addMarker = (event) => {
  if (!markerType.value || markerType.value === 'exit') return

  const coordinate = event.coordinate
  const feature = new Feature({
    geometry: new Point(coordinate),
    type: markerType.value,
  })

  markerSource.addFeature(feature)
}
// 初始化绘图图层
const initDrawLayer = () => {
  drawSource = new VectorSource()
  drawLayer = new VectorLayer({
    source: drawSource,
    style: new Style({
      fill: new Fill({
        color: 'rgba(255, 0, 0, 0.5)',
      }),
      stroke: new Stroke({
        color: 'blue',
        width: 2,
      }),
    }),
  })
  map.addLayer(drawLayer)
}

// 初始化地图时创建高亮图层
const initHighlightLayer = () => {
  highlightLayer = new VectorLayer({
    source: new VectorSource(),
    style: new Style({
      fill: new Fill({
        color: 'rgba(255, 0, 0, 0.5)',
      }),
      stroke: new Stroke({
        color: 'red',
        width: 2,
      }),
    }),
  })
  map.addLayer(highlightLayer)
}

// 获取当前城市信息
const fetchCurrentCity = async () => {
  try {
    const res = await getCityByIp()
    if (res?.city) {
      lives.value.city = res.city
      // 获取经纬度和adcode
      const geoRes = await getCityAdcode(res.city)
      if (geoRes?.geocodes?.length > 0) {
        const location = geoRes.geocodes[0].location
        const [lng, lat] = location.split(',').map(Number)
        // 保存adcode
        const adcode = geoRes.geocodes[0].adcode
        currentCityAdcode = adcode
        // 设置地图中心点
        map.getView().setCenter([lng, lat])
        map.getView().setZoom(6)
        // 高亮显示当前城市区域
        await highlightCityByAdcode(adcode)
      }
    }
  } catch (error) {
    console.error('获取城市信息失败:', error)
  }
}
// 高亮显示指定城市
const highlightCityByAdcode = async (adcode) => {
  if (!adcode || !highlightLayer) return

  try {
    // 清除之前的高亮
    highlightLayer.getSource().clear()

    // 构造城市GeoJSON数据URL
    const cityUrl = `https://geo.datav.aliyun.com/areas_v3/bound/${adcode}.json`
    const response = await fetch(cityUrl)
    if (!response.ok) {
      console.error('获取城市数据失败:', response.status)
      return
    }
    const cityData = await response.json()
    const features = new GeoJSON().readFeatures(cityData)

    if (features.length > 0) {
      highlightLayer.getSource().addFeatures(features)

      const feature = features[0]
      const geometry = feature.getGeometry()

      // 地图视图适应
      map.getView().fit(geometry.getExtent(), {
        padding: [50, 50, 50, 50],
        duration: 1000,
      })
    }
  } catch (error) {
    console.error('加载城市数据失败:', error)
  }
}

// 搜索城市处理函数
const handleSearchCity = async (cityName) => {
  if (!cityName) return
  try {
    // 调用api获取城市地理编码
    const res = await getCityAdcode(cityName)
    if (!res?.geocodes?.length || res.geocodes.length === 0) {
      ElMessage({
        message: '未搜索到该城市！',

        type: 'warning',
      })
      return
    }
    const location = res.geocodes[0].location
    const [lng, lat] = location.split(',').map(Number)
    const adcode = res.geocodes[0].adcode

    // 保存当前城市adcode
    currentCityAdcode = adcode
    // 更新城市名称
    lives.value.city = cityName

    // 设置地图中心点
    map.getView().animate({
      center: [lng, lat],
      zoom: 8,
      duration: 1000,
    })

    // 高亮显示搜索的城市区域
    await highlightCityByAdcode(adcode)
  } catch (error) {
    ElMessage({
      message: '未搜索到该城市！',
      type: 'error',
    })
  }
}

const initMouseInteraction = () => {
  // 添加监听器来处理鼠标悬停
  map.on('pointermove', (event) => {
    const feature = map.forEachFeatureAtPixel(event.pixel, (feature) => feature)
    if (feature && feature.getGeometry()) {
      if (highlightLayer.getSource().hasFeature(feature)) {
        const cityInfo = lives.value.city || '未知城市'
        // 获取要素的中心点
        const geometry = feature.getGeometry()
        const extent = geometry.getExtent()
        const center = getCenter(extent)
        const [lng, lat] = center
        // 更新提示框内容
        const content = document.getElementById('tooltip-content')
        if (content) {
          content.innerHTML = `
            <strong>当前城市:</strong> ${cityInfo}<br>
            <strong>经度:</strong> ${lng.toFixed(6)}<br>
            <strong>纬度:</strong> ${lat.toFixed(6)}
          `
        }
        //固定在城市中心点
        overlay.value.setPosition(center)
      }
    } else {
      overlay.value.setPosition(undefined)
    }
  })
}
// 处理绘图类型变化
const handleDrawTypeChange = (type) => {
  // 如果已存在绘图交互，则先移除
  if (drawInteraction) {
    map.removeInteraction(drawInteraction)
    drawInteraction = null
  }
  if (type === 'clear') {
    drawSource.clear()
    drawType.value = ''
    // 清除标签
    const overlaysToRemove = []
    map.getOverlays().forEach((overlay) => {
      if (overlay.getElement().classList.contains('measurement-label')) {
        overlaysToRemove.push(overlay)
      }
    })
    overlaysToRemove.forEach((overlay) => map.removeOverlay(overlay))
    return
  }

  // 添加新的绘图交互
  if (type) {
    let drawConfig = {
      source: drawSource,
    }
    // 根据不同类型设置配置
    switch (type) {
      case 'line':
        drawConfig.type = 'LineString'
        break
      case 'circle':
        drawConfig.type = 'Circle'
        break
      case 'polygon':
        drawConfig.type = 'Polygon'
        break
      case 'freehand':
        drawConfig.type = 'LineString'
        drawConfig.freehand = true
        break
      default:
        drawConfig.type = type.charAt(0).toUpperCase() + type.slice(1)
    }

    // 创建新的绘图交互
    drawInteraction = new Draw(drawConfig)
    drawInteraction.on('drawend', function (e) {
      // 直线测距
      if (type === 'line') {
        let f = e.feature
        let g = f.getGeometry()
        let length = getLength(g, { projection: map.getView().getProjection() })
        let position = g.getLastCoordinate()
        // 创建标签元素
        const labelElement = document.createElement('div')
        labelElement.className = 'measurement-label'
        labelElement.innerHTML = `<p>长度：${(length / 1000).toFixed(2)}km</p>`
        labelElement.style.cssText = `
          background: rgba(0, 0, 0, 0.7);
          color: white;
          padding: 4px 8px;
          border-radius: 4px;
          font-size: 12px;
        `
        // 创建overlay并设置位置和内容
        const measurementOverlay = new Overlay({
          element: labelElement,
          positioning: 'center-center',
        })
        measurementOverlay.setPosition(position)
        map.addOverlay(measurementOverlay)
      }
    })
    map.addInteraction(drawInteraction)
  }
}

onMounted(() => {
  initMap()
  initOverlay()
  initMouseInteraction()
  fetchCurrentCity()
})

//创建地图视图
const initMap = () => {
  const view = new View({
    projection: 'EPSG:4326',
    center: [116.4074, 39.9042], // 默认北京坐标
    zoom: 10,
  })

  // 创建地图实例
  map = new Map({
    target: mapContainer.value,
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
        }),
      }),
    ],
    view: view,
  })

  // 初始化图层
  initHighlightLayer()
  initDrawLayer()
  initMarkerLayer()

  map.getView().on('change:resolution', () => {
    const zoom = map.getView().getZoom()
    currentZoom.value = zoom
    if (zoom >= 12) {
      highlightLayer.setVisible(false)
    } else {
      highlightLayer.setVisible(true)
    }
  })
}
</script>

<style scoped>
.map-page {
  position: relative;
  width: 100%;
  height: 100vh;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

.top-bar {
  height: 80px;
  background-color: #4264fb;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 80px;
  padding: 0 20px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  z-index: 1000;
}

.city {
  color: #fff;
  font-size: 16px;
  font-weight: bold;
  margin-left: 20px;
}

.search-container {
  margin-right: 20px;
}

.select-container {
  margin-right: 20px;
}

.el-input__inner {
  border-radius: 4px;
  border: none;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
  background-color: white;
  color: #333;
}

.el-input__prefix {
  color: #666;
}

.el-input__icon {
  color: #666;
}

.el-select .el-input__inner {
  border-radius: 4px;
  border: none;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
  background-color: white;
  color: #333;
}

.el-select-dropdown {
  border-radius: 4px;
}

.map-container {
  width: 100%;
  height: calc(100vh - 80px);
}
</style>
